﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MinimalistFoodStreet.BackEnd.Repository.IRepository;

namespace MinimalistFoodStreet.BackEnd.Repository.Repository
{
    public class Repository<T> : IRepository<T> where T : class, new()
    {
        private readonly DbContext _dbContext;

        public Repository(DbContext dbContext)
        {
            _dbContext = dbContext;
        }
                
        public int Add(T t)
        {
            GetSet().Add(t);
            return Save();
        }

        public int Add(IEnumerable<T> ie)
        {
            GetSet().AddRange(ie);
            return Save();
        }

        public Task<int> AddAsync(T t)
        {
            GetSet().AddAsync(t);
            return SaveAsync();
        }

        public Task<int> AddAsync(IEnumerable<T> ie)
        {
            GetSet().AddRangeAsync(ie);
            return SaveAsync();
        }

        public int Delete(T t)
        {
            GetSet().Remove(t);
            return Save();
        }

        public int Delete(IEnumerable<T> ie)
        {
            GetSet().RemoveRange(ie);
            return Save();
        }

        public Task<int> DeleteAsync(T t)
        {
            GetSet().Remove(t);
            return SaveAsync();
        }

        public Task<int> DeleteAsync(IEnumerable<T> ie)
        {
            GetSet().RemoveRange(ie);
            return SaveAsync();
        }

        public DbContext GetDbContext()
        {
            return _dbContext;
        }

        public DbSet<T> GetSet()
        {
            return _dbContext.Set<T>();
        }

        public IQueryable<T> Pagination<TOrderKey>(Expression<Func<T, bool>> where, bool isAsc, Expression<Func<T, TOrderKey>> order, out int total, int page, int limit)
        {
            var iq = Query(where, isAsc, order);
            total = iq.Count();
            return iq.Skip((page - 1) * limit).Take(limit);
        }

        public IQueryable<T> Query()
        {
            return GetSet();
        }

        public IQueryable<T> Query(Expression<Func<T,bool>> where)
        {
            return GetSet().Where(where);
        }

        public IQueryable<T> Query<TOrderKey>(Expression<Func<T, bool>> where, bool isAsc, Expression<Func<T, TOrderKey>> order)
        {
            if (isAsc)
            {
                return Query(where).OrderBy(order);
            }
            else
            {
                return Query(where).OrderByDescending(order);
            }
        }

        public int Save()
        {
            return _dbContext.SaveChanges();
        }

        public Task<int> SaveAsync()
        {
            return _dbContext.SaveChangesAsync();
        }

        public int Update(T t)
        {
            GetSet().Update(t);
            return Save();
        }

        public int Update(IEnumerable<T> ie)
        {
            GetSet().UpdateRange(ie);
            return Save();
        }

        public Task<int> UpdateAsync(T t)
        {
            GetSet().Update(t);
            return SaveAsync();
        }

        public Task<int> UpdateAsync(IEnumerable<T> ie)
        {
            GetSet().UpdateRange(ie);
            return SaveAsync();
        }
    }
}
